package cn.lingyangwl.agile.msg.push.core.channel;

import cn.lingyangwl.agile.dynamic.config.core.*;
import cn.lingyangwl.agile.model.enums.*;
import cn.lingyangwl.agile.model.module.config.*;
import cn.lingyangwl.agile.model.module.config.param.*;
import cn.lingyangwl.agile.model.utils.*;
import cn.lingyangwl.agile.msg.push.api.constatnts.*;
import cn.lingyangwl.agile.msg.push.core.channel.client.*;
import cn.lingyangwl.framework.tool.core.exception.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author shenguangyang
 */
@Slf4j
@Component
public class ChannelClientManager {
    private static final Map<String, BaseMsgChannelClient> channelClientMap = new ConcurrentHashMap<>();

    @Resource
    private ConfigFactory configFactory;

    private void createClient(ChannelTypeEnum channelTypeEnum) {
        ConfigDefineEnum configDefine = channelTypeEnum.getConfigDefine();
        String cacheKey = ConfigUtils.getCacheKey(configDefine);

        // 获取一个被启用的渠道配置
        ConfigInfo config = configFactory.getConfigOfNonNull(configDefine);

        synchronized (cacheKey.intern()) {
            if (channelClientMap.containsKey(cacheKey)) {
                return;
            }
            // 这里获取到的配置是使能的配置, 所以根据使能的配置要获取到具体的渠道
            ChannelCodeEnum channelCode = ChannelCodeEnum.ofByBindConfig(config.getConfigKey());
            // 创建渠道客户端
            Class<? extends BaseMsgChannelClient> msgChannelClient = BaseMsgChannelClient.channelMap.get(channelCode);
            if (Objects.isNull(msgChannelClient)) {
                throw new BizException("消息渠道客户端 {} 尚未实现", channelCode);
            }

            // 获取使能的配置key
            ConfigKeyEnum enableConfigKey = ConfigKeyEnum.ofAndCheck(config.getConfigKey());
            MsgChannel msgChannel = new MsgChannel();
            msgChannel.setChannelCode(channelCode.getCode());
            msgChannel.setParamConfig(BaseConfigParam.jsonToObject(enableConfigKey, config.getConfigValue()));

            try {
                BaseMsgChannelClient baseMsgChannelClient = msgChannelClient.getDeclaredConstructor(MsgChannel.class)
                        .newInstance(msgChannel);
                baseMsgChannelClient.init();
                channelClientMap.put(cacheKey, baseMsgChannelClient);
            } catch (Exception e) {
                log.error("", e);
                throw new BizException(e.getMessage());
            }
        }
    }

    /**
     * 获取渠道客户端
     */
    public BaseMsgChannelClient getChannelClient(ChannelTypeEnum channelTypeEnum) {
        String cacheKey = ConfigUtils.getCacheKey(channelTypeEnum.getConfigDefine());
        if (!channelClientMap.containsKey(cacheKey)) {
            createClient(channelTypeEnum);
        }
        return channelClientMap.get(cacheKey);
    }

    public void deleteChannelClient(String configKey) {

        ConfigDefineEnum configDefine = ConfigDefineEnum.ofByKey(configKey);
        ChannelTypeEnum channelType = ChannelTypeEnum.ofByConfigGDefine(configDefine);
        if (Objects.isNull(channelType)) {
            return;
        }
        String cacheKey = ConfigUtils.getCacheKey(channelType.getConfigDefine());
        channelClientMap.remove(cacheKey);
        log.info("消息推送渠道 [{}]-[{}] 客户端被删除", configKey, cacheKey);
    }
}
